/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.ipti.br.tag.bo;

import org.ipti.br.tag.bean.dataManipulation.Month;
import org.ipti.br.tag.bean.dataManipulation.MonthlyFrequency;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import org.ipti.br.tag.dao.SimpleFrequencyFacade;
import org.ipti.br.tag.entity.Actor;
import org.ipti.br.tag.entity.Discipline;
import org.ipti.br.tag.entity.SimpleFrequency;
import org.ipti.br.tag.entity.Unity;
import org.ipti.br.tag.entity.UnitySchedule;
import org.ipti.br.tag.entity.enums.Reference;
import org.ipti.br.tag.entity.enums.WeekDay;
import java.io.FileOutputStream;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import javax.ejb.Stateless;
import javax.inject.Inject;

/**
 *
 * @author israel
 */
@Stateless
public class SimpleFrequencyBO implements Serializable {

    @Inject
    private SimpleFrequencyFacade simpleFrequencyDAO;
    @Inject
    private UnityScheduleBO unityScheduleBO;
    @Inject
    private ActorBO actorBO;

    public SimpleFrequencyFacade getSimpleFrequencyDAO() {
        return simpleFrequencyDAO;
    }

    public void create(SimpleFrequency simpleFrequency) {
        getSimpleFrequencyDAO().create(simpleFrequency);
    }

    public void edit(SimpleFrequency simpleFrequency) {
        getSimpleFrequencyDAO().edit(simpleFrequency);
    }

    public void remove(SimpleFrequency simpleFrequency) {
        getSimpleFrequencyDAO().remove(simpleFrequency);
    }

    public SimpleFrequency find(Object id) {
        return getSimpleFrequencyDAO().find(id);
    }

    public List<SimpleFrequency> findAll() {
        return getSimpleFrequencyDAO().findAll();
    }

    public SimpleFrequency findByFields(Calendar date, Long actorID,
            Reference reference, Long referenceID) {
        return getSimpleFrequencyDAO().findByFields(date, actorID, reference, referenceID);
    }

    public SimpleFrequency findByFields(SimpleFrequency sf) {
        return getSimpleFrequencyDAO().findByFields(sf.getFrequencyDate(), sf.getActor().getId(),
                sf.getReference(), sf.getReferenceID());
    }

    public List<Calendar> missedDaysPerReference(Reference reference, Long referenceID) {
        return getSimpleFrequencyDAO().missedDaysPerReference(reference, referenceID);
    }

    public List<SimpleFrequency> simpleFrequencysPerReferenceDates(Reference reference,
            Long referenceID, Calendar initialDate, Calendar finalDate) {
        return getSimpleFrequencyDAO().simpleFrequencysPerReferenceDates(reference, referenceID, initialDate, finalDate);
    }

    public List<SimpleFrequency> modifiedPerfFreqBetweenDate(Calendar initialDate, Calendar finalDate, Long serialNumber) {
        return getSimpleFrequencyDAO().modifiedPerfFreqBetweenDate(initialDate, finalDate, serialNumber);
    }

    public void loadFrequencys(MonthlyFrequency mf, Discipline discipline, Unity unity) {
        readFrequencys(new Load(), mf, discipline, unity);
    }

    public void saveFrequencys(MonthlyFrequency mf, Discipline discipline, Unity unity) {
        readFrequencys(new Save(), mf, discipline, unity);
    }

    public void replaceFrequencys(MonthlyFrequency mf, SimpleFrequency sf, Discipline discipline, Unity unity) {
        readFrequencys(new Replace(sf), mf, discipline, unity);
    }

    private void readFrequencys(Command cmd, MonthlyFrequency mf, Discipline discipline, Unity unity) {
        int count = 0;
        long reference = unity.getId();
        Reference refType = discipline == null ? Reference.UNITY : Reference.UNITY_SCHEDULE;
        Map<WeekDay, List<UnitySchedule>> weekDays = null;
        if (discipline != null) {
            weekDays = unityScheduleBO.map(unity, discipline);
        }

        SimpleFrequency sfTemp;
        Calendar c, d = Calendar.getInstance();
        List<Actor> actors = mf.getActors();
        for (int y = 0; y < mf.getDays().size(); y++) {
            c = Calendar.getInstance();
            c.setTime(mf.getDays().get(y));
            if (discipline != null) {
                if (y > 0) {
                    d.setTime(mf.getDays().get(y - 1));
                    if (c.get(Calendar.DAY_OF_MONTH) == d.get(Calendar.DAY_OF_MONTH)) {
                        count++;
                    } else {
                        count = 0;
                    }
                }
                reference = weekDays.get(WeekDay.getDay(c)).get(count).getId();
            }
            for (int i = 0; i < actors.size(); i++) {
                sfTemp = new SimpleFrequency(c, actors.get(i), null);
                sfTemp.setReference(refType);
                sfTemp.setReferenceID(reference);
                cmd.execute(sfTemp, mf, i, y);
            }
        }
    }

    public int getRepetitions(List<Date> days, int selected) {
        int i = selected, count = 0;
        Calendar actual = Calendar.getInstance(), before = Calendar.getInstance();
        ListIterator<Date> lIt = days.listIterator(selected + 1);
        actual.setTime(lIt.previous());
        if (lIt.hasPrevious()) {
            before.setTime(lIt.previous());
            while (actual.get(Calendar.DAY_OF_MONTH) == before.get(Calendar.DAY_OF_MONTH)) {
                count++;
                if (lIt.hasPrevious()) {
                    actual.setTime(before.getTime());
                    before.setTime(lIt.previous());
                } else {
                    break;
                }
            }
        }

        return count;
    }

    public void export(String path, int year, Month month, List<String> namesList, String unityName, List<Date> dayList) {
        Font titleFont = new Font(Font.FontFamily.TIMES_ROMAN, 16, Font.NORMAL, BaseColor.BLACK);
        Font defaultFont = new Font(Font.FontFamily.TIMES_ROMAN, 12, Font.NORMAL, BaseColor.BLACK);
        Font columnHeader = new Font(Font.FontFamily.TIMES_ROMAN, 10, Font.NORMAL, BaseColor.BLACK);

        try {
            Document document = new Document(PageSize.LETTER.rotate());
            PdfWriter.getInstance(document, new FileOutputStream(path));
            //document.setPageSize(PageSize.A4);
            document.setMargins(10, 10, 10, 10);
            document.setMarginMirroring(true);
            document.open();

            document.addTitle("Frequência " + unityName + " " + month.toString() + " " + year);
            document.addAuthor("IPTI");
            document.addCreator("IPTI");

            Paragraph title = new Paragraph("FREQUÊNCIA", titleFont);
            title.setAlignment(Element.ALIGN_CENTER);
            document.add(title);
            Paragraph space = new Paragraph();
            addEmptyLine(space, 1);
            document.add(space);

            document.add(new Paragraph("Unidade: " + unityName + ",  " + "Mês: " + month.toString() + ", " + "Ano: " + year, defaultFont));
            document.add(new Paragraph("* - Assinalar um item marca uma falta", defaultFont));
            document.add(space);

            float maxNameSize = 0F;
            for (String name : namesList) {
                if (((((float) name.length()) / 5) + 3) > maxNameSize) {
                    maxNameSize = (name.length() / 5) + 3;
                }
            }

            float columns[] = new float[dayList.size() + 1];
            columns[0] = maxNameSize;
            for (int i = 1; i < columns.length; i++) {
                columns[i] = 1F;
            }

            PdfPTable table = new PdfPTable(columns);
            table.setHorizontalAlignment(Element.ALIGN_CENTER);
            table.addCell(" ");
            table.setWidthPercentage(95);
            Calendar c = Calendar.getInstance();
            for (Date day : dayList) {
                c.setTime(day);
                PdfPCell cell = new PdfPCell(new Phrase(String.valueOf(c.get(Calendar.DAY_OF_MONTH)), defaultFont));
                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                table.addCell(cell);
            }

            Calendar c1 = Calendar.getInstance(), c2 = Calendar.getInstance();
            for (String name : namesList) {
                int count = 0;
                System.out.println("Name: " + name);
                PdfPCell cell = new PdfPCell(new Phrase(name, columnHeader));
                table.addCell(cell);
                table.addCell(" ");
                c1.setTime(dayList.get(0));
                for (int i = 1; i < dayList.size(); i++) {
                    cell = new PdfPCell(new Phrase(" "));
                    c2.setTime(dayList.get(i));
                    if (c1.get(Calendar.DAY_OF_MONTH) != c2.get(Calendar.DAY_OF_MONTH)) {
                        cell.setBackgroundColor((count % 2 == 0) ? BaseColor.LIGHT_GRAY : BaseColor.WHITE);
                        count++;
                    }
                    c1.setTime(c2.getTime());
                    table.addCell(cell);
                }
            }
            addEmptyRow(table, columns.length);
            addEmptyRow(table, columns.length);
            addEmptyRow(table, columns.length);
            addEmptyRow(table, columns.length);
            addEmptyRow(table, columns.length);
            addEmptyRow(table, columns.length);

            PdfPCell activityCell = new PdfPCell(new Phrase("Atividades"));
            activityCell.setRowspan(6);
            activityCell.setHorizontalAlignment(Element.ALIGN_CENTER);
            activityCell.setVerticalAlignment(Element.ALIGN_CENTER);
            table.addCell(activityCell);
            addEmptyRow(table, columns.length - 1);
            addEmptyRow(table, columns.length - 1);
            addEmptyRow(table, columns.length - 1);
            addEmptyRow(table, columns.length - 1);
            addEmptyRow(table, columns.length - 1);
            addEmptyRow(table, columns.length - 1);
            document.add(table);


            document.newPage();
            Paragraph replacementTitle = new Paragraph("REPOSIÇÃO", titleFont);
            title.setAlignment(Element.ALIGN_CENTER);
            document.add(replacementTitle);
            document.add(space);
            float replacementColumns[] = new float[3];
            replacementColumns[0] = 5F;
            replacementColumns[1] = 5F;
            replacementColumns[2] = 15F;
            PdfPTable replacementTable = new PdfPTable(replacementColumns);
            replacementTable.setHorizontalAlignment(Element.ALIGN_CENTER);
            PdfPCell cell = new PdfPCell(new Phrase("Data da Aula", defaultFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            replacementTable.addCell(cell);
            PdfPCell cell2 = new PdfPCell(new Phrase("Data da Reposição", defaultFont));
            cell2.setHorizontalAlignment(Element.ALIGN_CENTER);
            replacementTable.addCell(cell2);
            PdfPCell cell3 = new PdfPCell(new Phrase("Rubrica", defaultFont));
            cell3.setHorizontalAlignment(Element.ALIGN_CENTER);
            replacementTable.addCell(cell3);
            for (int i = 0; i < 10; i++) {
                addEmptyRow(replacementTable, replacementColumns.length);
            }
            document.add(replacementTable);
            Paragraph line = new Paragraph("_____________________________________________________");
            line.setAlignment(Paragraph.ALIGN_CENTER);
            Paragraph assing = new Paragraph("Assinatura");
            assing.setAlignment(Paragraph.ALIGN_CENTER);
            document.add(space);
            document.add(space);
            document.add(space);
            document.add(line);
            document.add(assing);

            document.close();
        } catch (Exception ex) {
        }
    }

    public void addEmptyRow(PdfPTable table, int columns) {
        for (int i = 0; i < columns; i++) {
            table.addCell(" ");
        }
    }

    private static void addEmptyLine(Paragraph paragraph, int number) {
        for (int i = 0; i < number; i++) {
            paragraph.add(new Paragraph(" "));
        }
    }

    private interface Command {

        public void execute(SimpleFrequency sf, MonthlyFrequency mf, int i, int y);
    }

    private class Save implements Command {

        private SimpleFrequency sfTemp;

        @Override
        public void execute(SimpleFrequency sf, MonthlyFrequency mf, int i, int y) {
            sfTemp = findByFields(sf);
            if (mf.getAssiduity()[i][y]) {
                System.out.println("TRUE " + i + " " + y);
                if (sfTemp == null) {
                    System.out.println("CRIANDO " + mf.getDays().toString());
                    create(sf);
                    getSimpleFrequencyDAO().flush();
                    System.out.println("CRIADO");
                } else {
                    edit(sfTemp);
                    System.out.println("EDITADO");
                }
            } else {
                if (sfTemp != null) {
                    System.out.println("QUERENDO REMOVER");
                    remove(sfTemp);
                }
            }
        }
    }

    private class Load implements Command {

        private SimpleFrequency sfTemp;

        @Override
        public void execute(SimpleFrequency sf, MonthlyFrequency mf, int i, int y) {
            sfTemp = findByFields(sf);
            if (sfTemp == null) {
                mf.getAssiduity()[i][y] = false;
            } else {
                mf.getAssiduity()[i][y] = true;
            }
        }
    }

    private class Replace implements Command {

        private SimpleFrequency sfTemp;

        public Replace(SimpleFrequency sfTemp) {
            this.sfTemp = sfTemp;
        }

        @Override
        public void execute(SimpleFrequency sf, MonthlyFrequency mf, int i, int y) {
            sf.setReference(sfTemp.getReference());
            sf.setReferenceID(sfTemp.getReferenceID());
            sfTemp = findByFields(sf);
            if (mf.getAssiduity()[i][y]) {
                if (sfTemp == null) {
                    create(sf);
                } else {
                    edit(sfTemp);
                }
            } else {
//                if (sfTemp != null) {
//                    remove(sfTemp);
//                }
            }
        }
    }
}
